package zheezes.socket;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Observable;
import java.util.Observer;

import org.apache.log4j.Logger;

import zheezes.protocol.Frame;
import zheezes.util.RandomUtil;
import zheezes.util.Util;


public abstract class PostOffice extends Observable implements Observer {
	public static final int ST_INIT = 0;
	public static final int ST_WORK = 1;
	public static final int ST_STNG = 2;
	public static final int ST_STED = 3;
	
	private boolean repress = false;
	
	protected int interrupt = 100;
	
	private static Logger logger = Logger.getLogger(PostOffice.class);

	private ThreadGroup group;

	protected List<Postman> postmen = new ArrayList<Postman>();
	
	private final Calendar startTime = Calendar.getInstance();
	
	public void init() {
		logger.info("init");
		group = new ThreadGroup("PostOffice");
		for (Postman postman : postmen) {
			// Postman postman = postmen.get(i);
			postman.addObserver(this);
			Thread th = new Thread(group, postman, postman.desc());
			th.start();
		}
	}

	public int liveCount() {
		int count = 0;
		for (Postman postman : postmen) {
			if (postman.live()) {
				count++;
			}
		}
		return count;
	}
	
	public int activeCount() {
		int count = 0;
		for (Postman postman : postmen) {
			if (postman.active()) {
				count++;
			}
		}
		return count;
	}
	
	public Transput send(Frame frame) {
		while (frame != null && liveCount() > 0) {
			for(int i : RandomUtil.randUnIntArray(0, postmen.size())) {
				Postman postman = postmen.get(i);
				if (postman.active()) {
					return postman.send(frame);
				}
			}
		}
		return null;
	}
	
	public void statistics() {
		long scnt = 0l;
		long rcnt = 0l;
		for (Postman p : postmen) {
			scnt += p.getSendCount();
			rcnt += p.getRecvCount();
		}
		logger.info(String.format("send[%d] recv[%d] in %d seconds", scnt, rcnt, (Calendar.getInstance().getTimeInMillis() - startTime.getTimeInMillis()) / 1000));
	}
	
	public void stop() {
		logger.info(String.format("postoffice stop, there is %d postman working", group.activeCount()));
		logger.debug("postoffice interrupt");
		for (Postman postman : postmen) {
			postman.stop();	
		}
		while (liveCount() > 0) {
			group.interrupt();
			// logger.debug(String.format("there is %d postman working", activeCount()));
			Util.msleep(interrupt);
		}
		group.destroy();
		statistics();
	}

	public void destroy() {
		stop();
	}
	
	public void update(Observable o, Object arg) {
		if (o instanceof Postman) {
			Postman postman = (Postman) o;
			synchronized (postmen) {
				if (postman.active() && repress) {
					logger.info("postoffice remove repress");
					repress = false;
					for (Postman p : postmen) {
						p.setSleeping(false);
					}
				} else if (activeCount() == 0) {
					if(!repress) {
						logger.info("postoffice repress");
						repress = true;
						boolean setted = false;
						for (Postman p : postmen) {
							if (!setted && p.live()) {
								p.setSleeping(false);
								setted = true;
							} else {
								p.setSleeping(true);
							}
						}
					} else {
						logger.info("postoffice has bean repressd");
					}
				}	
			}
		}
		setChanged();
		notifyObservers();
	}
}
